#!/usr/bin/env python3
"""The whole transcript of the live call, for Aux's transcript window (the speech bubble under the orb).

  aux-transcript [--env prod|staging|dev] [--call <id>] [--title]   # --call: a stored call, for testing

Prints one JSON object: {"call","participants":[{"id","name"}],"lines":[{"time","user_id","speaker","text"}]};
on failure {"error": "..."} with exit 1. With no live call it falls back to the most recent stored call.
--title prints {"call","title"} instead: one short sentence on what the call is about, written by a fast
tool-less Claude call and cached per call in $AUX_HOME/transcript-titles; it is rewritten only once the call
has said a good deal more than when it was last written.
"""
import argparse
import json
import subprocess
import sys
from pathlib import Path

# Inside an app bundle (Tuple.app/Contents/Helpers/Tuple Aux.app) a __pycache__ write is macOS's
# "python3 was prevented from modifying apps" prompt; the import never needs one.
sys.dont_write_bytecode = True
sys.path.insert(0, str(Path(__file__).resolve().parent))
from aux_context import CLIS, AUX, capture, resolve_env, run  # noqa: E402

TITLES = AUX / "transcript-titles"
TITLE_MODEL = "haiku"
# Rewrite the title once the transcript has grown by this many lines and by half since it was written.
TITLE_GROWTH = 30


def fail(msg):
    print(json.dumps({"error": msg}))
    return 1


def latest_call(cli):
    code, out, _ = run([cli, "capture", "list", "--format", "json"], timeout=15)
    try:
        calls = json.loads(out) if code == 0 else []
    except ValueError:
        return None
    calls = sorted(calls, key=lambda c: c.get("started_at") or "", reverse=True)
    return calls[0].get("call_id") if calls else None


def title(call, lines):
    """{"call","title"} for the transcript, from the cache while it still fits."""
    cache = TITLES / f"{call}.json"
    try:
        old = json.loads(cache.read_text())
    except (OSError, ValueError):
        old = {}
    n = len(lines)
    if old.get("title") and (n - old.get("lines", 0) < TITLE_GROWTH or n < old.get("lines", 0) * 1.5):
        return {"call": call, "title": old["title"]}
    if not lines:
        return {"call": call, "title": ""}
    # The opening and the latest speech, so a long call is not one wall of text.
    sample = lines if n <= 200 else lines[:60] + lines[-140:]
    said = "\n".join(f"{l['speaker']}: {l['text']}" for l in sample)
    prompt = ("Below is the transcript of a Tuple call so far. Write ONE short sentence (10 words or fewer, with a verb) "
              "saying what the call is about, as a window title, like \"Eli walks the team through round 5 of the "
              "focus slider\". Lead with the main thread, not a list of topics. Name people by first name. No quotes, "
              "no preamble, no trailing period.\n\n" + said)
    cmd = ["claude", "-p", "--model", TITLE_MODEL, "--tools", "", "--no-session-persistence", "--strict-mcp-config",
           "--output-format", "text", prompt]
    try:
        p = subprocess.run(cmd, cwd=str(AUX), capture_output=True, text=True, timeout=60)
    except (OSError, subprocess.TimeoutExpired):
        return {"call": call, "title": old.get("title", "")}
    text = (p.stdout.strip().splitlines() or [""])[0].strip().strip('"').rstrip(".")
    if p.returncode != 0 or not text:
        return {"call": call, "title": old.get("title", "")}
    TITLES.mkdir(parents=True, exist_ok=True)
    cache.write_text(json.dumps({"title": text, "lines": n}))
    return {"call": call, "title": text}


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--env", choices=CLIS)
    ap.add_argument("--call")
    ap.add_argument("--title", action="store_true")
    a = ap.parse_args()

    env, cli, call = resolve_env(a.env)
    if a.call:
        call = a.call
    if not cli:
        return fail("No Tuple CLI installed.")
    call = call or latest_call(cli)
    if not call:
        return fail("No call to show.")
    recs = capture(cli, call)
    people, lines = {}, []
    for r in recs:
        d = r.get("data") or {}
        user = d.get("user") or {}
        if user.get("id"):
            people[user["id"]] = user.get("full_name") or user.get("email") or str(user["id"])
        if r.get("type") != "transcription_finished":
            continue
        text = (d.get("text") or "").strip()
        if not text:
            continue
        if d.get("user_id") and d.get("speaker"):
            people.setdefault(d["user_id"], d["speaker"])
        lines.append({"time": d.get("start") or r.get("time"), "user_id": d.get("user_id"),
                      "speaker": d.get("speaker") or people.get(d.get("user_id")) or "?", "text": text})
    if a.title:
        print(json.dumps(title(call, lines)))
        return 0
    print(json.dumps({"call": call, "participants": [{"id": k, "name": v} for k, v in people.items()],
                      "lines": lines}))
    return 0


if __name__ == "__main__":
    sys.exit(main())
